package thread

import (
	"go_jvm/element"
	"math"
)

type OperandStack struct {
	// 记录栈顶位置
	Size uint
	// 操作数栈的大小是编译器确定的 可以用Slot[]来实现
	Slots []Slot
}

func NewOperandStack(maxStack uint64) *OperandStack {
	if maxStack > 0 {
		return &OperandStack{Slots: make([]Slot, maxStack)}
	}
	return nil
}

func (self *OperandStack) PushInt(val int32) {
	self.Slots[self.Size].num = val
	self.Size++
}

func (self *OperandStack) PopInt() int32 {
	self.Size--
	return self.Slots[self.Size].num
}
func (self *OperandStack) PushFloat(val float32) {
	self.Slots[self.Size].num = int32(math.Float32bits(val))
	self.Size++
}

func (self *OperandStack) PopFloat() float32 {
	self.Size--
	return math.Float32frombits(uint32(self.Slots[self.Size].num))
}

func (self *OperandStack) PushLong(val int64) {
	self.Slots[self.Size].num = int32(val)
	self.Slots[self.Size+1].num = int32(val >> 32)
	self.Size += 2
}

func (self *OperandStack) PopLong() int64 {
	low := self.Slots[self.Size].num
	high := self.Slots[self.Size-1].num
	self.Size -= 2
	return int64(high)<<32 | int64(low)
}

func (self *OperandStack) PushDouble(val float64) {
	bits := math.Float64bits(val)
	self.PushLong(int64(bits))
}

func (self *OperandStack) PopDouble() float64 {
	bits := uint64(self.PopLong())
	return math.Float64frombits(bits)
}

func (self *OperandStack) PushRef(val *element.Object) {
	self.Slots[self.Size].ref = val
	self.Size++
}

func (self *OperandStack) PopRef() *element.Object {
	self.Size--
	r := self.Slots[self.Size].ref
	self.Slots[self.Size].ref = nil
	return r
}
